home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
016a
/
del10.zip
/
DEL!.ASM
next >
Wrap
Assembly Source File
|
1991-12-08
|
15KB
|
601 lines
PAGE 60,132
TITLE DEL! replacement for DOS DEL command
Comment |
┌─────────────────────┐
│ DEL! C:\MySub\X.Txt │
│ DEL! C:\MySub\X?.* │
│ DEL! C:MySub\*.* │
│ DEL! X.TXT │
│ ^watch the space│
└─────────────────────┘
Written in Microsoft Assembler MASM 5.0, MASM 6.0 and OPTASM 1.61b
written 1991 December 7
by Roedy Green
Canadian Mind Products
#168 - 1020 Mainland Street
Vancouver, BC
Canada V6B 2T4
(604) 684-6529
This program is copyrighted but free. The source and object
code may be used for any purpose except military. You are free
to copy it, sell it, modify it, or cannibalize it. You may even
take out the credits if you want. The only restriction is
that you must make sure none of it is ever used for a military
purpose.
Version History:
****************
Version 1.0 1991/12/07 released to BIX
This is the initial version.
Purpose
*******
DEL! is very similar to the normal MS or PC DOS DEL command,
however DEL! is somewhat more powerful.
DEL! is just a heavy duty form of DEL for use in BAT files such
as installs. Its personality is roughly modeled on Arnold's
Schwartzenegger's character in Terminator III.
DEL! is taciturn. It does not complain if the file has already
been deleted -- no more:
IF EXIST X.TXT DEL X.TXT
just
DEL! X.TXT
DEL! never generates an error message, even when it can find no
files to delete. If you give it the name of a subdirectory
(without *.*) to delete it does nothing, and makes no complaint.
However if it cannot delete any files, it sets errorlevel to 1.
DEL! is ruthless. It does not pause for confirmation on DEL! *.*
No more SAY! "Y" 13 | DEL *.* >NUL
just DEL! *.*
DEL! is tough. It also deletes hidden and read-only files.
DEL! is respectful of authority. It will NOT delete system files.
DEL! is light on its feet. It is only 385 bytes.
DEL! is slower than DEL since it is must be loaded each time,
whereas DEL is internal to DOS.
Tools
*****
DOS offers a set of awkward tools for this job:
----
We can use the old FCB style delete.
AH 13h
DS:DX Pointer to an unopened FCB
returns:
AL 00h If file deleted
FFh If file not found
The catches are:
Only works on the current directory.
Does not work on hidden or read-only files.
Only allows ? as a wild card, not *
----
We can use the Handle style UNLINK delete
AH 41h
DS:DX Pointer to filespec (ASCIIZ string)
returns;
AX Error code, if CF is set
2 File not found
3 Path not found
5 Access denied
The catches are:
Does not allow any wildcards.
Does not work on read-only files.
----
To make read-only files deletable, we can change their attributes
AH 43h
AL 01h
CX Desired attributes
DS:DX Pointer to filespec (ASCIIZ string)
returns:
AX Error code, if CF is set
The catches are:
Does not allow any wildcards.
----
To search with general wildcards: find first:
AH 4Eh
CX File attribute
DS:DX Pointer to filespec (ASCIIZ string)
returns
AX Error code, if CF is set
2 File not found
3 Path not found
18 No more files to be found
Find next
AH 4Fh
returns
AX Error code, if CF is set
18 No more files to be found
the DTA looks like this:
Offset Size Description
00h 21 Used by DOS for find-next processing
15h 1 Attribute of file found
16h 2 Time stamp of file
18h 2 Date stamp of file
1Ah 4 File size in bytes
1Eh 13 Filename and extension, as an ASCIIZ string
e.g. X.TXT_ <-null
Notes an How DEL! Works
***********************
DEL! parses the command line looking for a file or wildcard
name.
Initialize the errorlevel to 1, presume failure.
We do a find first (function 4E) with hidden, read-only etc
attributes turned on so we see those files too. We don't peek
at subdirs or system files. We feed it the ENTIRE filename --
including any wildcards and filename.
If there were no files we quit.
We split out the drive:directory part of the name with
possible trailing \, with wildcards or filename stripped off.
e.g. C:\MYSUB\ C:\ C: \MYSUB\ MYSUB\SUB2\ null
In other words, all ready to glue on the filename.
AGAIN:
DOS gives us just the filename and extension, not the drive or
directory. Compose its fullname by concatenating the filename
onto the end of the drive/dirname.
If it is a read-only file we remove read-only status with
function 43h.
Then we delete it with delete it with function 41h.
If we were successful deleting, change the errorlevel to 0
We then continue with a FIND NEXT 4F
If there were no more files we quit. If there was another, we
loop back to AGAIN.
Future Improvements
*******************
This program currently does THREE DOS function calls to get rid
of each file:
1. find next
2. fix attribute (for read only)
3. delete file
DOS ends up SEARCHING for the file to delete FROM SCRATCH!
What would be more efficient is to use the FCB-type delete,
which can wipe out all the files in one DOS call. The catch is
you still have to use the current method to clean up afterwards
since the FCB method cannot deal with hidden or read-only files.
The FCB speed up works like this:
Figure out which drive we are working with.
Get the current diretory on that drive and save it away.
Change the directory to the one where the files are we want to
kill. If there is no such directory, give up.
Peel off he wildcard tail from the command line and give that to
the FCB delete.
Then continue with the handle method to get rid of any hidden or
read-only files.
| ; End of long comment
stack segment stack ; keep MS link happy by providing null stack
stack ends
;==============================================================
CODE SEGMENT PARA ; start off in code.
;==============================================================
data segment word ; provide a separate DATA segment
; Even though it appears in the source
; before the code, it the COM file it
; will appear at the end. This is as dodge
; to avoid forward references that confuse
; MASM.
FirstData Label Word
data endS
;==============================================================
com group code,data
ASSUME CS:COM,DS:COM,ES:COM
ORG 100H
Start:
;==============================================================
; REGISTER CONVENTIONS
; all registers are trashable in calls except BX CX and DI
; BX often points to the start of part of the command string.
; CX often counts number of chars in part of the command string.
; DI often points to the last char of some part of the command string.
; Because this is a com file, all segment registers are
; stable equal to CS:
;======================================
Data Segment
EVEN
DTA LABEL BYTE ; disk transfer area
; Used in Find First Match
DB 21 DUP (0) ; reserved for DOS
Fattrib DB 0 ; attribute byte
FTime DW 0 ; file Time in directory form
FDate DW 0 ; file Date in directory form
FSize DW 0 ; 32 bit file size
DW 0
FName DB 13 DUP(0) ; ASCIIZ file name and extension
; NOT parsed into fixed length file+ext
; NOTE DOS WILL NOT TELL US THE DIR NAME
; OR DRIVE.
DirStart DW 0 ; addr where directory name starts
DirTack DW 0 ; addr byte just after dirname, wher
; we can tack on a filename.
; Note we build pick out the filename
; as a subset of the command line.
; We pick out he dirname as a subset
; of the filename in the command line.
; We build the complete filenames in
; the command line too!
; We don't need any string variables at all!
Errorlevel DB 1 ; DOS exit code. Presume failure.
; banner never displayed, but embedded in file.=
BannerMsg DB '░▒▓█ DEL! 1.0 █▓▒░',13,10
DB 13,10
DB 'Copyright 1991 Roedy Green Canadian Mind Products',13,10
DB 'May be freely copied and used for any purpose but military.',13,10,'$'
Data EndS
;======================================
MAIN PROC
call Parse ; parse command line
; DS:BX len CX contains ASCIIZ string
; stripped of lead/trail blanks
; gets drive:dir\filename
Call FindFirst ; find first file that matches wildcard
; spec, or perhaps a perfect match.
jc Done ; if no files, we are done
Call GetDirName ; strip off the filename/wildcard
; leaving just the drive:directory
NextFile:
Call BuildFilename ; glue filename onto tag end of dirname.
; leave asciiz in DS:bx
Call RidRO ; Get rid of the file, even if it was
; read-only.
Call FindNext ; find next file matching wildcards
Jnc NextFile
Done:
mov ah,04Ch
mov al,errorlevel ; quit with 0 errorlevel if killed at least
; one file, 1 otherwise
int 21h ; exit to DOS
MAIN ENDP
;======================================
Parse PROC NEAR
; Parse the command line to remove lead/trail blanks
; and terminate by 2 nulls.
; sample inputs
; DEL! C:\MySub\X.TXT
; DEL! MySub2
; DEL!
; DEL! D:\
; DEL! D:
;
; When Done DS:BX points to start of string.
; String will be terminated by 2 nulls
; CX counts bytes in string exclusive of nulls
; counted string at HEX 80 PSP
; contains command line.
; Preceeded by unwanted spaces.
; possibly followed by unwanted spaces.
; currently missing a trailing null.
xor ch,ch
mov cl,ds:80h
mov bx,81H
call Mleading ; get rid of leading blanks
call MTrailing ; get rid of trailing blanks
mov di,bx ; calc addr of byte just past end
add di,cx
mov word ptr [di],0 ; plop in pair of nulls after string
ret
Parse ENDP
;=======================================
MLeading PROC Near
; on entry BX is addr of string, CX its length
; trims off any leading blanks, leaving result in BX CX
; length may also be 0 or 1, but not -ve
; If the entire string is blank the result is the null string
mov di,bx
mov al,20h ; AL = blank -- the search char
jcxz mleading2 ; jump if null string
repe scasb ; scan ES:DI forwards till hit non blank
; DI points just after it (wrap ok)
; CX is one too small, or 0 if none found
je mleading1 ; jump if entire string was blank
inc cx ; CX is length of remainder of string
mleading1:
dec di ; DI points to non-blank
mleading2:
mov bx,di ;a put address back
ret
MLeading ENDP
;========================================
MTrailing PROC Near
; on entry BX is addr of string, CX its length
; trims off any trailing blanks, leaving result in BX CX
; length may also be 0 or 1, but not -ve
; If the entire string is blank the result is the null string
mov di,bx
add di,cx ; calc addr last char in string
dec di
mov al,20h ; AL = blank -- the search char
jcxz mtrailing1 ; jump if null string
std
repe scasb ; scan ES:DI backwards till hit non blank
; DI points just ahead of it (wrap ok)
; CX is one too small, or 0 if none found
cld
je mtrailing1 ; jump if whole string was blank
inc cx
mtrailing1:
ret
MTrailing ENDP
;========================================;====
FindFirst Proc
; Find first file that matches our wildcard spec
; on input DS:bx length cx is the filename.
; preserves DS:bx cx
push bx
push cx
lea dx,DTA
mov ah,1Ah ; set up DTA for DOS to report its findings
int 21h
mov dx,bx
mov cx,03h ; find read only and hidden files
; 01 bit 0 = RO √
; 02 bit 1 = hidden √
; 04 bit 2 = system
; 08 bit 3 = volume label
; 10 bit 4 = subdir
; 20 bit 5 = archive
mov ah,4Eh
int 21h ; find first
; STC notes trouble
; DTA contains results
pop cx
pop bx
ret
FindFirst EndP
;=======================================
GetDirName PROC Near
; on input DS:BX length CX points to filename on command line
; We want to strip it back to drive:dirname
mov DirStart,bx ; save pointer to the C:
call StripDrive ; peel off the leading C:
; remainder is DS:bx len cx
call StripFile ; peel off the trailing X.TXT *.* etc.
; remainder is DS:bx len cx, last di
; di points to last char of string
inc di ; point just past end where can tack on.
mov DirTack,di
ret
GetDirName ENDP
;=======================================
StripDrive PROC Near
; Remove leading drive C: if any
; XXX.TXT -> XXX.TXT
; C: -> null
; C:\ -> \
; C:\SUB1\SUB2\X.XX -> \SUB1\SUB2\X.X
; ^ ^ ^
; a b c
; input DS:BX=a CX=length a..c
; results DS:BX=b CX=length b..c
cmp byte ptr [bx+1],':'
jne HasNoDrive
add bx,2
sub cx,2
HasNoDrive:
ret
StripDrive ENDP
;=======================================
StripFile PROC Near
; Remove trailing filename, leaving just the dirname.
; C:X -> C:
; C:\X.X -> C:\
; C:\SUB1\SUB2\X.XX -> C:\SUB1\SUB2\
; ^ ^ ^ ^
; a b c d
; input DS:BX=b CX=length b..d
; results DS:BX=b CX=length b..c di=c
mov di,bx
add di,cx
dec di ; point to last char of string d
std ; scan back
mov al,'\'
repne scasb
cld
jne NoSlash
inc di
inc cx
NoSlash:
ret
StripFile ENDP
;=======================================
BuildFilename Proc
; Tack filename from the DTA onto the end of the dirname in
; the command line forming an ASCIIZ string. Leave result in
; DS:BX
lea si,Fname ; source in DTA
mov di,DirTack ; where to tack on next char
; target is in the command line.
; we overwrite wildcard, but it is no longer
; needed.
mov cx,7 ; 13=8+3+null by words
rep movsw ; copy over
mov bx,DirStart ; DS:bx is start of full generated filename.
ret
BuildFilename EndP
;=======================================
RidRO PROC NEAR
; get rid of file whose asciiz name is in DS:BX
; get rid of read only status and delete it.
mov dx,bx
test Fattrib,1 ; attribute of file found in DTA
; is it read only?
jz PlainFile
; was read-only, turn that off
xor cx,cx ; CX=attrib
mov ax,4301h ; change attribute to vanilla
int 21h
Plainfile:
mov ah,41h ; delete it
int 21h
jc WouldNotDie
mov errorlevel,0 ; record success
WouldNotDie:
ret
RidRO ENDP
;=======================================================
FindNext Proc
; Find next file that matches our wildcard spec
; we no longer need the wildcard spec
mov ah,4Fh
int 21h ; find next
; STC notes trouble
; DTA contains results
ret
FindNext EndP
;=======================================
CODE ENDS
END Start